// $Id: Traces.cs 10 2008-02-29 15:58:02Z mcartoixa $
/*
 *  Copyright (C) 2007 Noury Solutions
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 */
#pragma warning disable 1587
/** \file
 * \brief Assembly traces.
 *
 * \author $Author: mcartoixa $
 * \date $Date: 2008-02-29 16:58:02 +0100 (ven., 29 févr. 2008) $
 * \version $Revision: 10 $
 */
#pragma warning restore 1587

using System;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;

namespace Salamanca.DataAccess
{
#if (NET_CF)
    internal class TraceSwitch
    {
    }

    internal enum TraceLevel
    {
    }
#endif


    internal static class Traces
    {
        public static string GetCategory(TraceSwitch sw, TraceLevel level)
        {
#if (!NET_CF)
            return string.Format(
                CultureInfo.CurrentCulture,
                "[{0:s}] [Thread <0x{1:X4}>] [Trace <{2}>, Level <{3}>]",
                DateTime.Now,
                Thread.CurrentThread.ManagedThreadId,
                sw.DisplayName,
                sw.Level
            );
#else
            return string.Empty;
#endif
        }

        [Conditional("NET_1_0"), Conditional("NET_1_1"), Conditional("NET_2_0"), Conditional("NET_3_0")]
        public static void TraceDatabaseActionIf(TraceSwitch sw, TraceLevel level, IDbConnection connection, string action)
        {
#if (!NET_CF)
            if ((connection!=null) && (connection.Database!=null))
                Trace.WriteLineIf(
                    sw.Level>=level,
                    string.Format(
                        CultureInfo.CurrentCulture,
                        "<{0}> {1}",
                        connection.Database,
                        action
                    ),
                    Traces.GetCategory(sw, TraceLevel.Info)
                );
            else
                Trace.WriteLineIf(
                    sw.Level>=level,
                    string.Format(
                        CultureInfo.CurrentCulture,
                        "<> {0}",
                        action
                    ),
                    Traces.GetCategory(sw, TraceLevel.Info)
                );
#endif
        }

        [Conditional("NET_1_0"), Conditional("NET_1_1"), Conditional("NET_2_0"), Conditional("NET_3_0")]
        public static void TraceBeforeCommand(TraceSwitch sw, IDbCommand command, string method)
        {
#if (!NET_CF)
            Traces.TraceDatabaseActionIf(sw, TraceLevel.Info, command.Connection, method);
            Trace.WriteLineIf(sw.TraceInfo, command.CommandText);
            if (sw.TraceInfo)
            {
                Trace.Indent();
                foreach (IDataParameter p in command.Parameters)
                    Traces.TraceParameter(p);
                Trace.Unindent();
            }
#endif
        }

        [Conditional("NET_1_0"), Conditional("NET_1_1"), Conditional("NET_2_0"), Conditional("NET_3_0")]
        public static void TraceAfterCommand(TraceSwitch sw, IDbCommand command, string method)
        {
#if (!NET_CF)
            if (sw.TraceInfo)
            {
                Trace.WriteLine(method);
                Trace.Indent();
                foreach (IDataParameter p in command.Parameters)
                    if ((p.Direction==ParameterDirection.InputOutput) || (p.Direction==ParameterDirection.Output) || (p.Direction==ParameterDirection.ReturnValue))
                        Traces.TraceParameter(p);
                Trace.Unindent();
            }
#endif
        }

        [Conditional("NET_1_0"), Conditional("NET_1_1"), Conditional("NET_2_0"), Conditional("NET_3_0")]
        public static void TraceParameter(IDataParameter parameter)
        {
#if (!NET_CF)
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "{0,-20} : {1,-10}| {2,-12}| {3}", parameter.ParameterName, parameter.DbType, parameter.Direction, GetValueTrace(parameter.Value)));
#endif
        }

        public static string GetValueTrace(object value)
        {
            string ret=string.Empty;

            if (value!=null)
            {
                if (value is Array)
                {
                    System.Array a=(System.Array)value;

                    StringBuilder sb=new StringBuilder("{");
                    int up=a.GetUpperBound(0);
                    for (int i=a.GetLowerBound(0); i<Math.Min(up, _MaxArrayElements); ++i)
                    {
                        sb.Append(GetValueTrace(a.GetValue(i)));
                        if (i<up-1)
                            sb.Append(", ");
                    }
                    if (a.GetLength(0)>_MaxArrayElements)
                        sb.AppendFormat(CultureInfo.CurrentCulture, "(+{0})...", a.GetLength(0)-_MaxArrayElements);

                    sb.Append("}");

                    ret=sb.ToString();
                } else if (value is string)
                {
                    string s=(string)value;
                    if (s.Length>_MaxStringLength)
                        ret=string.Format(CultureInfo.CurrentCulture, "\"{0}\"(+{1})...", s.Substring(0, _MaxStringLength), s.Length-_MaxStringLength);
                    else
                        ret=string.Format(CultureInfo.CurrentCulture, "\"{0}\"", value);
                } else
                    ret=value.ToString();
            }

            return ret;
        }

        private const int _MaxArrayElements=8;
        private const int _MaxStringLength=20;

    }
}
